Skip to content

feat(gcp): exclude project ids#746

Merged
ShubhamRasal merged 4 commits into
devfrom
feat/gcp-exclude-project-ids
Apr 16, 2026
Merged

feat(gcp): exclude project ids#746
ShubhamRasal merged 4 commits into
devfrom
feat/gcp-exclude-project-ids

Conversation

@girish-cheedala
Copy link
Copy Markdown
Contributor

@girish-cheedala girish-cheedala commented Apr 13, 2026

Summary

  • Add exclude_project_ids option for GCP org-level discovery to skip specific projects
  • Mutually exclusive with project_ids, requires organization_id
  • Uses per-project Asset API calls (Mode 2) on remaining projects — excluded projects are never queried, reducing API calls
  • Returns error if all projects are excluded

Changes

  • pkg/schema/schema.go — YAML unmarshaling for exclude_project_ids
  • pkg/providers/gcp/gcp.go — parsing, validation, exclude filtering in org provider
  • pkg/providers/gcp/project_scope_test.go — tests for parsing, validation, filtering
  • PROVIDERS.md — documented new option with example config

Test plan

  • Unit tests pass (go test ./pkg/providers/gcp/ -v)
  • Build passes (go build ./...)
  • WIF integration test: excluded pd-oss from org 292477584000, confirmed 54/55 projects scanned, pd-oss absent from results
  • Validation: both project_ids + exclude_project_ids → error
  • Validation: exclude_project_ids without organization_id → error
  • Validation: all projects excluded → error

Summary by CodeRabbit

  • New Features

    • Added exclude_project_ids parameter for GCP provider to exclude specific projects from organization-wide discovery scans. Requires organization_id and is mutually exclusive with project_ids.
  • Documentation

    • Updated GCP configuration guide with the new parameter details and included YAML configuration example.

- Implemented logic to validate mutually exclusive project IDs and exclusion lists in the GCP provider.
- Added support for excluding project IDs based on organization ID requirements.
- Introduced new helper functions to retrieve and parse excluded project IDs from options.
- Enhanced tests to cover exclusion scenarios and validation errors.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Walkthrough

Added an organization-level GCP option exclude_project_ids enabling organization-wide discovery to skip specified project IDs; implemented validation (mutually exclusive with project_ids, requires organization_id), parsing/normalization, enrichment/filtering of discovered projects, schema unmarshalling support, docs, and tests.

Changes

Cohort / File(s) Summary
Documentation
PROVIDERS.md
Documented exclude_project_ids option, behavior (organization-only, mutually exclusive with project_ids), and added an organization-level YAML example.
Schema Parsing
pkg/schema/schema.go
Treat exclude_project_ids as a list-like field during YAML unmarshalling so it is normalized (comma-separated string) like other ID/list fields.
GCP Provider Logic
pkg/providers/gcp/gcp.go
Added validation in New to enforce mutual exclusivity and require organization_id when exclude_project_ids is set; added getExcludeProjectIDsFromOptions parsing/deduping; updated organization discovery path to enrich exclude IDs with project numbers, filter discovered projects, rebuild provider.projectScope, and error if no projects remain.
Tests
pkg/providers/gcp/project_scope_test.go
Added tests for parsing/deduplication of exclude_project_ids, validation errors (mutual exclusivity and missing organization_id), and filtering behavior to ensure excluded projects are omitted from scope.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hopped through configs, tidy and spry,
Skipping projects beneath the sky;
Numbers and names I sort and prune,
Quietly clearing late-night rune,
A soft nibble, a clever try.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(gcp): exclude project ids' directly and clearly summarizes the main feature addition: introducing GCP project exclusion capability for organization-level discovery.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/gcp-exclude-project-ids

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/schema/schema.go (1)

243-267: ⚠️ Potential issue | 🟠 Major

Preserve scalar exclude_project_ids values during YAML unmarshalling.

Line 243 routes the new key through an array-only branch. With YAML like exclude_project_ids: "sandbox,legacy", this case writes nothing into OptionBlock, so GetMetadata("exclude_project_ids") returns false and the exclusion/validation path never runs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/schema/schema.go` around lines 243 - 267, The current branch for keys
("account_ids","exclude_account_ids","urls","services","project_ids","exclude_project_ids")
only handles value as []interface{} and silently drops scalar YAML values;
update the branch in the code that processes key/value (where ob is
*OptionBlock, key and value are available, and valueArr/strArr are used) to also
handle scalar types (string, int, float64) when value is not a slice: convert
the scalar to the same string format used for array elements (including zero-pad
for account_ids/exclude_account_ids), assign it to (*ob)[key] (e.g., as the
single-item comma string), and keep the existing error handling for unsupported
types so exclude_project_ids and similar scalar YAML values are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/providers/gcp/gcp.go`:
- Around line 214-217: The hasExclude branch currently returns a generic error
when organization_id is missing; change that to return the typed missing-key
error used elsewhere by returning &schema.ErrNoSuchKey{Name: "organization_id"}
instead of errkit.New(...). Locate the check around hasExclude and
options.GetMetadata("organization_id") in pkg/providers/gcp/gcp.go and replace
the generic error return with the typed schema.ErrNoSuchKey to make callers able
to distinguish "missing config" from other validation failures; ensure you still
use options.GetMetadata to read the config (supporting $VAR env syntax) and only
return ErrNoSuchKey when the metadata key is absent.
- Around line 814-846: The code currently leaves provider.projectScope nil when
project listing fails or excludes remove all projects, causing Resources() to
fall back to org-wide discovery; change the logic in the block that handles
getExcludeProjectIDsFromOptions(options) so that whenever enumeration fails or
the filtered projects slice is empty you assign provider.projectScope to an
explicit empty project scope (e.g., newProjectScope([]string{}) or an
emptyProjectScope sentinel) instead of leaving it nil; ensure this is done both
after applying the exclude filter and in the error path after
enrichWithProjectNumbers (use newProjectScope/emptyProjectScope and set
provider.projectScope accordingly) so that Resources() cannot revert to
organization-wide Asset API accidentally.

---

Outside diff comments:
In `@pkg/schema/schema.go`:
- Around line 243-267: The current branch for keys
("account_ids","exclude_account_ids","urls","services","project_ids","exclude_project_ids")
only handles value as []interface{} and silently drops scalar YAML values;
update the branch in the code that processes key/value (where ob is
*OptionBlock, key and value are available, and valueArr/strArr are used) to also
handle scalar types (string, int, float64) when value is not a slice: convert
the scalar to the same string format used for array elements (including zero-pad
for account_ids/exclude_account_ids), assign it to (*ob)[key] (e.g., as the
single-item comma string), and keep the existing error handling for unsupported
types so exclude_project_ids and similar scalar YAML values are preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3ca65efe-ad32-4216-9316-2bd476e74332

📥 Commits

Reviewing files that changed from the base of the PR and between da6b66e and 67842c4.

📒 Files selected for processing (4)
  • PROVIDERS.md
  • pkg/providers/gcp/gcp.go
  • pkg/providers/gcp/project_scope_test.go
  • pkg/schema/schema.go

Comment thread pkg/providers/gcp/gcp.go
@neo-by-projectdiscovery-dev
Copy link
Copy Markdown

neo-by-projectdiscovery-dev Bot commented Apr 13, 2026

Neo - PR Security Review

No security issues found

Comment @pdneo help for available commands. · Open in Neo

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
pkg/providers/gcp/gcp.go (2)

214-217: ⚠️ Potential issue | 🟡 Minor

Return a typed missing-key error for organization_id.

This path still returns a generic validation error, so callers cannot distinguish a missing required key from other config failures. Return &schema.ErrNoSuchKey{Name: "organization_id"} here instead.

As per coding guidelines, "Parse provider configuration via block.GetMetadata(key); support environment variables using $VAR syntax; return &schema.ErrNoSuchKey{Name: key} for missing required config".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/providers/gcp/gcp.go` around lines 214 - 217, Replace the generic
validation error returned when organization_id is missing with the typed schema
error so callers can detect the missing key; inside the hasExclude branch where
options.GetMetadata("organization_id") is checked, return
&schema.ErrNoSuchKey{Name: "organization_id"} instead of errkit.New(...). Ensure
the change is applied in the same conditional that references hasExclude and
options.GetMetadata so callers receive the schema.ErrNoSuchKey sentinel.

816-836: ⚠️ Potential issue | 🔴 Critical

Fail closed when exclude_project_ids is set but project enumeration is empty.

If listing projects failed earlier, this block is skipped, provider.projectScope stays nil, and Resources() falls back to organizations/<org> discovery. That re-includes the projects the user explicitly asked to exclude. When exclusions are configured, treat an empty or unresolved project list as an error or an explicit empty scope instead of falling back.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/providers/gcp/gcp.go` around lines 816 - 836, When exclude_project_ids
(excludeIDs) is provided but the projects slice is empty you must fail instead
of falling back to org discovery; add an early check after project enumeration
such that if len(excludeIDs) > 0 && len(projects) == 0 you return an error
(e.g., via errkit.New) indicating that no projects remain or enumeration failed,
so the code in the newProjectScope/excludeScope branch is not the only path that
triggers this failure; update the logic around newProjectScope/excludeScope and
the existing check that returns when len(projects) == 0 so the provider does not
silently revert to organizations/<org> discovery when exclusions were requested.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/providers/gcp/gcp.go`:
- Around line 838-848: When configuredProjects is empty, the unscoped discovery
path currently calls manager.Projects.List() without an organization filter;
change the call that builds the project iterator to include the filter
"parent.type:organization parent.id:<organizationID>" so only projects under the
requested organization are returned. Locate the branch where configuredProjects
is checked and manager.Projects.List() is invoked (the code that later
constructs scope via newProjectScope(...) and assigns provider.projectScope),
and replace the plain List() invocation with a filtered
List().Filter(fmt.Sprintf("parent.type:organization parent.id:%s",
organizationID)) so subsequent enrichWithProjectNumbers(...) and projectScope
assignment operate only on organization-scoped projects.

---

Duplicate comments:
In `@pkg/providers/gcp/gcp.go`:
- Around line 214-217: Replace the generic validation error returned when
organization_id is missing with the typed schema error so callers can detect the
missing key; inside the hasExclude branch where
options.GetMetadata("organization_id") is checked, return
&schema.ErrNoSuchKey{Name: "organization_id"} instead of errkit.New(...). Ensure
the change is applied in the same conditional that references hasExclude and
options.GetMetadata so callers receive the schema.ErrNoSuchKey sentinel.
- Around line 816-836: When exclude_project_ids (excludeIDs) is provided but the
projects slice is empty you must fail instead of falling back to org discovery;
add an early check after project enumeration such that if len(excludeIDs) > 0 &&
len(projects) == 0 you return an error (e.g., via errkit.New) indicating that no
projects remain or enumeration failed, so the code in the
newProjectScope/excludeScope branch is not the only path that triggers this
failure; update the logic around newProjectScope/excludeScope and the existing
check that returns when len(projects) == 0 so the provider does not silently
revert to organizations/<org> discovery when exclusions were requested.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f91a2cfc-e9d0-4278-bf9e-0eaea9b7f868

📥 Commits

Reviewing files that changed from the base of the PR and between 67842c4 and 3aafa33.

📒 Files selected for processing (1)
  • pkg/providers/gcp/gcp.go

Comment thread pkg/providers/gcp/gcp.go
Comment thread pkg/providers/gcp/gcp.go Outdated
Comment thread pkg/providers/gcp/gcp.go Outdated
Comment thread pkg/providers/gcp/gcp.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/providers/gcp/gcp.go`:
- Around line 814-852: The code currently builds a per-project scope from
whatever is in the projects slice even if the Projects.List().Pages(...)
pagination failed part-way; change the logic so you only construct and assign
provider.projectScope when you know the project listing completed successfully
(or otherwise handle partial results explicitly). In practice, propagate or
check the pagination error from Projects.List().Pages(...) (or set a
"listingComplete" boolean) and if the listing was incomplete do not call
newProjectScope/enrichWithProjectNumbers/assign provider.projectScope; instead
return an error or keep global scope so Resources() does not silently skip later
pages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bc384241-3068-49f7-9422-6f6a88a23f4e

📥 Commits

Reviewing files that changed from the base of the PR and between 3aafa33 and e576191.

📒 Files selected for processing (1)
  • pkg/providers/gcp/gcp.go

Comment thread pkg/providers/gcp/gcp.go
@ShubhamRasal ShubhamRasal merged commit d5d9036 into dev Apr 16, 2026
10 checks passed
@ShubhamRasal ShubhamRasal deleted the feat/gcp-exclude-project-ids branch April 16, 2026 07:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants